/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package ua.yandex.MyList;

public class MyLinkedList implements MyList {

    private static class Node {

        private Node next;
        private Object elem;

        public Node() {
            this.next = null;
            this.elem = null;
        }

        public void set(Object e) {
            this.elem = e;
        }

        public Object take() {
            return this.elem;
        }

        public void setNext(Node nextNode) {
            this.next = nextNode;
        }

        public Node takeNext() {
            return this.next;
        }

    }

    private Node head;
    private Node tail;
    private int size;

    public MyLinkedList() {
        this.head = null;
        this.tail = null;
        this.size = 0;
    }

    protected boolean badIndex(int index) {

        return index > this.size() - 1 || index < 0;
    }

    private Node getElIndex(int index) {
        int i = 0;
        Node current = this.head;
        while (i != index) {
            i++;
            current = current.takeNext();
        }
        return current;
    }

    @Override
    public void add(Object e) {
        Node addToList = new Node();
        addToList.set(e);
        addToList.setNext(null);
        this.size++;
        if (this.head == null) {
            this.head = addToList;
            this.tail = addToList;
        } else {
            this.tail.setNext(addToList);
            this.tail = addToList;
        }

    }

    @Override
    public int size() {

        return this.size;
    }

    @Override
    public boolean isEmpty() {
        return this.size() == 0;
        // return this.head == null;
    }

    @Override
    public void addAll(Object[] c) {
        for (Object i : c) {
            this.add(i);
        }
    }

    @Override
    public int indexOf(Object o) {
        Node current = this.head;
        int k = 0;
        if (this.head == null) {
            return -1;
        } else {
            if (o != null) {
                while (current != null) {
                    if (current.take().equals(o)) {
                        return k;
                    }
                    k++;
                    current = current.takeNext();
                }
            } else {
                while (current != null) {
                    if (current.take() == o) {
                        return k;
                    }
                    current = current.next;
                    k++;
                }
            }
        }
        return -1;
    }

    @Override
    public void clear() {
        this.head = null;
        this.tail = null;
        this.size = 0;
    }

    @Override
    public void add(int index, Object e
    ) {
        if (index != 0 && badIndex(index - 1)) {
            throw new IllegalArgumentException("Les than list size");
        }
        Node current = this.head;
        this.size++;
        if (index == 0) {
            Node addList = new Node();
            addList.set(e);
            addList.setNext(this.head);
            this.head = addList;
        } else {
            current = this.getElIndex(index - 1);

            Node addList = new Node();
            addList.set(e);
            addList.setNext(current.takeNext());
            current.setNext(addList);
        }
    }

    @Override
    public Object get(int index
    ) {
        if (this.head == null) {
            throw new IllegalArgumentException("Les than list size");
        } else if (badIndex(index)) {
            throw new IllegalArgumentException("Les than list size");
        }
        return this.getElIndex(index).take();

    }

    @Override
    public Object remove(int index
    ) {
        if (this.head == null) {
            throw new IllegalArgumentException("Les than list size");
        } else if (badIndex(index)) {
            throw new IllegalArgumentException("Les than list size");
        }
        Node current = this.head;
        this.size--;
        if (index == 0) {
            Node returnable = this.head;
            current = current.takeNext();
            this.head = current;
            return returnable.take();
        } else if (index < this.size() - 1) {
            current = this.getElIndex(index - 1);
            Node returnable = current.takeNext();
            current.setNext(current.takeNext().takeNext());
            return returnable.take();
        } else {
            current = this.getElIndex(index - 1);
            Node returnable = current.takeNext();
            //current.set(null);
            return returnable.take();
        }
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        int i = 0;
        Node current = this.head;
        while (i + 1 <= this.size()) {
            i++;
            sb.append(current.take());
            sb.append(",");
            current = current.takeNext();
        }
        return sb.toString();
    }

    @Override
    public Object[] toArray() {
        Object[] o = new Object[this.size()];
        Node current = this.head;
        for (int i = 0; i < this.size(); i++) {
            o[i] = current.take();
            current = current.takeNext();

        }
        return o;
    }

    @Override
    public void set(int index, Object e
    ) {
        if (this.head == null) {
            throw new IllegalArgumentException("Les than list size");
        } else if (badIndex(index)) {
            throw new IllegalArgumentException("Les than list size");
        }
        Node current = this.head;
        current = this.getElIndex(index);
        current.set(e);
    }

    @Override
    public void addAll(int index, Object[] c) {
        if (badIndex(index)) {
            throw new IllegalArgumentException("Les than list size");
        }
        MyLinkedList addList = new MyLinkedList();
        this.size += c.length;
        for (int j = 0; j < c.length; j++) {
            addList.add(c[j]);
        }
        Node current = this.head;
        current = this.getElIndex(index - 1);
        addList.tail.setNext(current.takeNext());
        current.setNext(addList.head);
        //current.setNext(null);
        //for (int j = 0; j < c.length; j++) {this.add(index + j, c[j]);}
    }

    public void addFirst(Object e) {
        Node addList = new Node();

        addList.set(e);
        this.size++;
        if (this.head == null) {
            this.head = addList;
            this.tail = addList;
        } else {
            addList.setNext(this.head);
            this.head = addList;
        }
    } // - добавляет элемент в начало

    public Object getFirst() {
        return this.get(0);
    }

    public Object getLast() {
        return this.get(this.size() - 1);
    }

    public Object removeFirst() {
        return this.remove(0);
    }

    public Object removeLast() {
        return this.remove(this.size() - 1);
    }
}
